/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ortustve;

import ortustve.media.favoriteexcluder.FavoriteExcluder;
import ortustve.property.OrtusProperty;
import java.io.File;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import ortustve.daemon.cronDaemon;
import ortustve.daemon.processDaemon;
import ortustve.daemon.tcpDaemon;
import ortustve.db.IEngine;
import ortustve.db.derbyengine;
import ortustve.db.h2engine;
import ortustve.ui.menu.usermenu;
import ortustve.ui.theme.usertheme;
import sagex.api.Global;

/**
 *
 * @author jphipps
 */
public class Ortus extends ortusvars {

    private static Ortus INSTANCE = null;
    private volatile boolean ortus_setup_complete = false;
    private String BasePath = null;
    private String ConfigPath = null;
    Map<String,OrtusProperty> PropertyMap = Collections.synchronizedMap(new HashMap(5));
    Map<String,Identity> IdentityMap = Collections.synchronizedMap(new HashMap(5));
    Map<String,String> MACMap = Collections.synchronizedMap(new HashMap(5));
    private usermenu MenuAPI = null;
    private FavoriteExcluder FavoriteExcluderAPI = null;
    private usertheme ThemeAPI = null;
    private IEngine DBAPI = null;
    private cronDaemon CronServerAPI = null;
    private processDaemon ProcessServerAPI = null;
    private tcpDaemon TcpServerAPI = null;
    public volatile HashMap<String,Boolean> modules = new HashMap<String,Boolean>();
    private logger OrtusLogAPI = null;

    private Ortus() {
	    System.out.println("Ortus Super Class starting");
    }

    public static Ortus getInstance() {
        if ( INSTANCE == null ) {
            synchronized(Ortus.class) {
                if ( INSTANCE == null )
                   INSTANCE = new Ortus();
            }
        }
        return INSTANCE;
    }


	public void Configure(String context, String activatemodules) {

		ortustve.api.StoreUIContextName(context);

		OrtusLogAPI = new logger();

		OrtusLogAPI.getLogger().info("Ortus v2.0: Setup is running for context: " + context);

		String[] activatemods = activatemodules.split("\\|");
		for ( String x: activatemods) {
			if( ! x.isEmpty()) {
				OrtusLogAPI.getLogger().info("Ortus: Activating module: " + x.toLowerCase());
				modules.put(x.toLowerCase(),true);
			}
		}

		OrtusLogAPI.getLogger().info("Ortus: GetUIContextName: " + ortustve.api.GetUIContextName());
		OrtusLogAPI.getLogger().info("Ortus: Version: " + ortustve.api.GetVersionFull());

		String SageWorking = System.getProperty("user.dir") + java.io.File.separator + "STVs" + java.io.File.separator + "SageTV3" + java.io.File.separator + "Ortus";

		String MACaddr = null;

		if (Global.IsClient(ortustve.api.GetUIContext()) || Global.IsServerUI(ortustve.api.GetUIContext())) {
			if ( Global.IsClient(ortustve.api.GetUIContext()))
				OrtusLogAPI.getLogger().trace("Ortus: Is a Client");
			if ( Global.IsServerUI(ortustve.api.GetUIContext()))
				OrtusLogAPI.getLogger().trace("Ortus: Is a Server");
			try {
				InetAddress address = InetAddress.getLocalHost();
				OrtusLogAPI.getLogger().info("Ortus: net got address: " + address);
				NetworkInterface ni = NetworkInterface.getByInetAddress(address);
				byte[] mac = ni.getHardwareAddress();
				for (int i = 0; i < mac.length; i++) {
					if (i == 0) {
						MACaddr = (String.format("%02X", mac[i]));
					} else {
						MACaddr = MACaddr + String.format("%02X", mac[i]);
					}
				}
			} catch (Exception e) {
				MACaddr = "Unknown";
				OrtusLogAPI.getLogger().warn( "Ortus: Exception: " + e);
			}
		} else {
			OrtusLogAPI.getLogger().trace("Ortus: Is an Extender/Placeshifter");
			MACaddr = context;
		}

		ortustve.api.SetSageProperty("ortus/mac", MACaddr);
		ortustve.api.SetSageProperty("ortus/context", context);
		OrtusLogAPI.getLogger().info("Ortus: MAC address: " + MACaddr);
		BasePath = SageWorking;
		OrtusLogAPI.getLogger().info("Ortus: BasePath: " + BasePath);
		ConfigPath = SageWorking + java.io.File.separator + "Configuration" + java.io.File.separator + MACaddr;
		OrtusLogAPI.getLogger().info("Ortus: ConfigPath: " + ConfigPath);

		File cp = new File(ConfigPath);

		if (!cp.exists()) {
			cp.mkdirs();
		}

		PropertyMap.put(context, new OrtusProperty(ConfigPath));
		PropertyMap.get(context).SetProperty("ortus/mac", MACaddr);
		PropertyMap.get(context).SetProperty("ortus/basepath", BasePath);
		PropertyMap.get(context).SetProperty("ortus/configpath", ConfigPath);

		MACMap.put(context, MACaddr);

		IdentityMap.put(context, new Identity(MACaddr));

  	        if ( ortustve.api.GetProperty("remotehost",null) == null) {
		    if ( Global.IsClient(ortustve.api.GetUIContext()) || Global.IsServerUI(ortustve.api.GetUIContext()))
			    ortustve.api.SetProperty("remotehost", Global.GetServerAddress());
		    else
			    ortustve.api.SetProperty("remotehost", "None");
	        }

		if ( modules.get("favoriteexcluder") != null)
			StartFavoriteExcluder();
		
		if ( modules.get("menu") != null)
			StartMenu();

		if ( modules.get("theme") != null)
			StartTheme();

		if ( modules.get("cron") != null) {
			StartCron();
		}

		if ( modules.get("process") != null) {
			StartProcess();
		}

		if ( modules.get("tcp") != null) {
			StartTcp();
		}

		if ( modules.get("db") != null ) {
			StartDB();
			OrtusLogAPI.getLogger().trace(" Adding cache build to queue");
			new Thread(new ortustve.daemon.daemonProcess(new Object[] { "ortus.api.PreLoadCache" }),"cachePreload").start();
//			OrtusLogAPI.getLogger().trace("Adding SageMedia Cache load to queue");
//			new Thread(new ortus.daemon.daemonProcess(new Object[] { "ortus.api.LoadSageMediaCache"}), "SageMediaPreload").start();
		} else {
		    OrtusLogAPI.getLogger().info("Ortus: using Wiz.bin");
		}

		
		OrtusLogAPI.getLogger().info("Ortus: environment: Loaded for " + MACaddr + " with name: " + IdentityMap.get(context).GetClientName());

		if ( ! ortus_setup_complete ) {
		        Runtime.getRuntime().addShutdownHook(new Thread() {
			   public void run() {
	   			StopFavoriteExcluder();
				StopMenu();
				StopTheme();
				StopCron();
				StopProcess();
				StopTcp();
				StopDB();
			   }
			});
		}
		ortus_setup_complete = true;
	}

	public void StartFavoriteExcluder() {
		if ( FavoriteExcluderAPI == null ) {
			OrtusLogAPI.getLogger().info("Ortus: Starting module: FavoriteExcluder");
			FavoriteExcluderAPI = new FavoriteExcluder(BasePath);
			modules.put("favoriteexcluder", true);
		}
	}

	public void StopFavoriteExcluder() {
		if ( FavoriteExcluderAPI != null ) {
			OrtusLogAPI.getLogger().info("Ortus: Stopping module: FavoriteExcluder");
			FavoriteExcluderAPI.Shutdown();
			FavoriteExcluderAPI = null;
			modules.remove("favoriteexcluder");
		}
	}

	public void StartMenu() {
		if ( MenuAPI == null ) {
			OrtusLogAPI.getLogger().info("Ortus: Starting module: Menu");
			MenuAPI = new usermenu(ConfigPath);
			modules.put("menu", true);
		}
	}

	public void StopMenu() {
		if ( MenuAPI != null ) {
			OrtusLogAPI.getLogger().info("Ortus: Stopping module: Menu");
			MenuAPI.Shutdown();
			MenuAPI = null;
			modules.remove("menu");
		}
	}

	public void StartTheme() {
		if ( ThemeAPI == null) {
			OrtusLogAPI.getLogger().info("Ortus: Starting module: Theme");
			ThemeAPI = new usertheme(BasePath);
			modules.put("theme",true);
		}
	}

	public void StopTheme() {
		if ( ThemeAPI != null) {
			OrtusLogAPI.getLogger().info("Ortus: Stopping module: Theme");
			ThemeAPI.Shutdown();
			ThemeAPI = null;
			modules.remove("theme");
		}
	}

	public void StartCron() {
		if ( CronServerAPI == null) {
			OrtusLogAPI.getLogger().info("Ortus: Starting module: Cron");
			CronServerAPI = new cronDaemon();
			CronServerAPI.start();
			modules.put("cron",true);
			if ( ! ortustve.api.GetProperty("remotehost").equalsIgnoreCase("none"))
				if ( (Boolean)ortustve.process.executeRemote(new Object[] { "ortus.onlinescrapper.api.IsindexMediaRunning"}))
					ortustve.api.AddCron(5, "ortus.api.CronUpdateScanStatus", new Object[] {});
		}
	}

	public void StopCron() {
		if ( CronServerAPI != null) {
			OrtusLogAPI.getLogger().info("Ortus: Stopping module: Cron");
			CronServerAPI.Shutdown();
			CronServerAPI = null;
			modules.remove("cron");
		}
	}
	public void StartProcess() {
		if ( ProcessServerAPI == null) {
			OrtusLogAPI.getLogger().info("Ortus: Starting module: Process");
			ProcessServerAPI = new processDaemon();
			ProcessServerAPI.start();
			modules.put("process",true);
		}
	}

	public void StopProcess() {
		if ( ProcessServerAPI != null) {
			OrtusLogAPI.getLogger().info("Ortus: Stopping module: Process");
			ProcessServerAPI.Shutdown();
			ProcessServerAPI = null;
			modules.remove("process");
		}
	}

	public void StartTcp() {
		if ( TcpServerAPI == null) {
			OrtusLogAPI.getLogger().info("Ortus: Starting module: Tcp");
			TcpServerAPI = new tcpDaemon();
			TcpServerAPI.start();
			modules.put("tcp",true);
		}
	}

	public void StopTcp() {
		if ( TcpServerAPI != null) {
			OrtusLogAPI.getLogger().info("Ortus: Stopping module: Tcp");
			TcpServerAPI.Shutdown();
			TcpServerAPI = null;
			modules.remove("tcp");
		}
	}
	
	public void StartDB() {
	    if ( DBAPI == null) {
		    OrtusLogAPI.getLogger().info("Ortus: using SQL Database");
		    if ( ortustve.api.GetProperty("dbtype","h2").equals("h2")) {
			    if ( ortustve.api.GetProperty("h2protocol",null) == null) {
				    if ( Global.IsClient(ortustve.api.GetUIContext())) {
					    ortustve.api.SetProperty("h2protocol", "jdbc:h2:tcp://" + Global.GetServerAddress() + "/ortusDB/ortusDB");
				    } else {
					    ortustve.api.SetProperty("h2protocol", "jdbc:h2:ortusDB/ortusDB");
				    }
			    }

			    DBAPI = new h2engine();
		    } else if ( ortustve.api.GetProperty("dbtype","h2").equals("derby")) {
			    if ( ortustve.api.GetProperty("derbyprotocol",null) == null) {
				    if ( Global.IsClient(ortustve.api.GetUIContext()) || Global.IsServerUI(ortustve.api.GetUIContext())) {
					    ortustve.api.SetProperty("derbyprotocol", "jdbc:derby:tcp://" + Global.GetServerAddress() + "/ortusDB/ortusDB");
				    } else {
					    ortustve.api.SetProperty("derbyprotocol", "jdbc:derby:ortusDB");
				    }
			    }
			    DBAPI = new derbyengine();
		    }
		    List<Object> result = DBAPI.executeSQLQuery("SELECT schema_name  FROM INFORMATION_SCHEMA.SCHEMATA where schema_name = 'SAGE'");
		    OrtusLogAPI.getLogger().trace(" schema result count: " + result.size() );
		    if ( result.size() < 1) {
			OrtusLogAPI.getLogger().info("Ortus: Database not found, creating...");
			DBAPI.createDB();
		    }
		    modules.put("db",true);
	    }
	}

	public void StopDB() {
		if ( DBAPI != null) {
			OrtusLogAPI.getLogger().info("Ortus: Stopping module: DB");
			DBAPI.ShutdownDatabase();
			DBAPI = null;
			modules.remove("db");
		}
	}

    public void Shutdown() {
        PropertyMap.remove(ortustve.api.GetSageProperty("ortus/mac",""));
        IdentityMap.remove(ortustve.api.GetSageProperty("ortus/mac", ""));
        MACMap.remove(ortustve.api.GetSageProperty("ortus/mac",""));
	CronServerAPI.Shutdown();
    }

    public String GetMACAddress() {
          return MACMap.get(ortustve.api.GetUIContextName());
    }

    public List<String> GetClients() {
	    List<String> clientnames = new ArrayList<String>();
	    Object[] clients = IdentityMap.keySet().toArray();
	    for ( Object x : clients) {
		    clientnames.add(IdentityMap.get((String)x).GetClientName());
	    }
	    return clientnames;
    }

    public logger getLogger() {
	    return OrtusLogAPI;
    }
    
    public OrtusProperty getProperty() {
        OrtusProperty x = PropertyMap.get(ortustve.api.GetUIContextName());
        if ( x == null)
            OrtusLogAPI.getLogger().trace("GetProperty: is null");
        return x;
    }

    public usermenu getMenu() {
        return MenuAPI;
    }

    public Identity getIdentity() {
        return IdentityMap.get(ortustve.api.GetUIContextName());
    }

    public FavoriteExcluder getFavoriteExcluder() {
        return FavoriteExcluderAPI;
    }

    public usertheme getTheme() {
        return ThemeAPI;
    }

    public IEngine getDB() {
        return DBAPI;
    }

    public cronDaemon getCronServer() {
	    return CronServerAPI;
    }

    public processDaemon getProcessServer() {
	    return ProcessServerAPI;
    }

    public tcpDaemon getTcpServer() {
	    return TcpServerAPI;
    }
    
    public boolean IsOrtusInitialized() {
        return ortus_setup_complete;
    }
}
